home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Franz PD / Franz PD Disk #002 (19xx)(Amiga User Group Deutschland e.V.).zip / Franz PD Disk #002 (19xx)(Amiga User Group Deutschland e.V.).adf / DirUtil / du.c < prev    next >
C/C++ Source or Header  |  1986-10-22  |  41KB  |  1,223 lines

  1. /* DIRectory UTILity II -
  2.         This program is in the public domain. Nicotra source downloaded
  3.         from local BBS and modified by Jobusch. Word is Nicotra recently
  4.         released an improved version (1.3). Hope his code is better than
  5.         it was in 1.0. NO guarentees...if you blow up a disk with this
  6.         program, it's your own damn fault.
  7.  
  8.         Original Version (Directory Utilitity 1.0) by Chris Nicotra
  9.  
  10.         10/6/86  Rich Medved, CIS 72366,540.  Added TYPE function. Added
  11.         support for df2:.  Cleaned up some of the warning msg. from the
  12.         compilier.  Come on guys, let's start using revision numbers.
  13.         Seeing "this is a new version" on the bds. is getting confusing.
  14.         For a start, this is now version 1.4
  15.  
  16.         Revisions/Enhancements/Fixes by David L. Jobusch
  17.                                    ...umn-cs!isucs1!jobusch
  18.  
  19.     1.4.1:
  20.         Do not clear enabled items after they have been typed. Dirutil
  21.         previously did a (time consuming) directory search after the
  22.         files had been typed. This drove me nearly crazy as I have
  23.         some directories with 100 entries.
  24.  
  25.         Added new functions to the type command. '<' goes back to
  26.         the beginning of the file. 'b' goes back about 1000 bytes.
  27.         The last one should really be one page, but I was to lazy.
  28.  
  29.         Type now recognizes that lines longer than 79 characters wrap
  30.         around and should be counted as more than one line. The algorithm
  31.         could stand some improvements...
  32.  
  33.         Cleaned up the show command a bit. Dirutil looks for the file
  34.         "c:show" on startup. If this file is found then the SHOW ILBM
  35.         command will be enabled. To make this work do:
  36.         copy showilbm c:show
  37.         
  38.                 17-NOV-86 Johan Widen
  39.                 62/20 Second Ave, Mt Lawley, WA 6050
  40.        */
  41.  
  42. #include <exec/types.h>
  43. #include <exec/memory.h>
  44. #include <intuition/intuition.h>
  45. #include <intuition/intuitionbase.h>
  46. #include <graphics/gfxbase.h>
  47. #include <stdio.h>
  48. #include <libraries/dos.h>
  49. #include <libraries/dosextens.h>
  50. #include <workbench/startup.h>
  51.  
  52. #define INTUITION                0x00000001
  53. #define GRAPHICS                 0x00000002
  54. #define WINDOW                   0x00000004
  55. #define INITDIRLOCKOK            0x00000008
  56. #define  BRK                     0x3
  57. #define  ESC                     0x1b
  58. #define SHOW             1
  59. #ifdef SHOW
  60. #define SHOWCMD "c:show"        /* Name of the actual program   */
  61. #define SHOWNAMELENGTH 10       /* Make changes? Set this!      */
  62. #endif
  63.  
  64. #define FBSIZE  (long)(sizeof (struct FileInfoBlock))
  65. #define MAXFILE 100             /* Maximum files to look at in directory */
  66. #define MAXFNAME 10             /* Maximum files to show at once         */
  67. #define MAXCHAR  30             /* Max file name length                  */
  68. #define MAXCD    255            /* Max current dir name length           */
  69.  
  70. #define SLIDE_GADGET    0
  71. #define ERR_GADGET      3
  72. #define CURDIR_GADGET   4       /* Gadget labels                         */
  73. #define CPDIR_GADGET    5
  74. #define DF0_GADGET      6
  75. #define DF1_GADGET      7
  76. #define DF2_GADGET      8
  77. #define HD0_GADGET      9
  78. #define RAM_GADGET      10
  79. #define ALL_GADGET      11
  80. #define CLEAR_GADGET    12
  81. #define COPY_GADGET     13
  82. #define DELETE_GADGET   14
  83. #define RENAME_GADGET   15
  84. #define GETDIR_GADGET   16
  85. #define MAKEDIR_GADGET  17
  86. #define DELETEDIR_GADGET 18
  87. #define PARENT_GADGET   19
  88. #define ROOT_GADGET     20
  89. #define LIST_GADGET     21
  90. #define TYPE_GADGET     22
  91. #define BUT_FIRST DF0_GADGET
  92.  
  93. #ifdef SHOW
  94. #define SHOW_GADGET     23
  95. #define FIRST_GADGET    But_gad[17]
  96. #define KILL_SHOW       But_gad[17]
  97. #define BUT_LAST        SHOW_GADGET
  98. #endif
  99. #ifndef SHOW
  100. #define FIRST_GADGET    But_gad[16]
  101. #define BUT_LAST        TYPE_GADGET
  102. #endif
  103.  
  104. #define WinIDCMP  CLOSEWINDOW | REFRESHWINDOW | GADGETUP | MOUSEBUTTONS
  105.  
  106.  
  107. extern struct FileHandle  *Open();
  108. extern APTR AllocMem();
  109. struct IntuitionBase *IntuitionBase;
  110. struct GfxBase *GfxBase;
  111. struct IntuiMessage *message;
  112. struct RastPort *rp;
  113. struct Window *w;
  114.  
  115. /************************************************************************/
  116. /*              Source/Destination string gadgets                       */
  117. /************************************************************************/
  118. USHORT str_pairs [] = { 0,0,  590,0,  590,9,  0,9,  0,0,};
  119. struct Border str_border =
  120. {
  121.     -1,-1,              /* Leftedge, Topedge */
  122.      1, 1, JAM1,        /* FrontPen, BackPen, Drawmode */
  123.      5,                 /* Number of Pairs */
  124.     (APTR) &str_pairs,  /* XY, Pointer to XY pairs */
  125.     NULL,               /* More borders */
  126. };
  127.  
  128. /* Error display */
  129. char err_buf[MAXCD+1];
  130. struct StringInfo err_str = 
  131. { &err_buf, NULL, 0, MAXCD+1,   0, 0, 0, 0, 2,0, NULL, 0, NULL, };
  132.  
  133. struct Gadget Err_gad =
  134. {
  135.         NULL, /* last in the list of gadgets */
  136.         21,122,
  137.         588, 9,
  138.         GADGHCOMP, GADGIMMEDIATE | RELVERIFY | STRINGCENTER,
  139.         STRGADGET,
  140.         (APTR) &str_border,
  141.         NULL,
  142.         NULL,   /* Intuitext pointer */
  143.         0,
  144.         &err_str,
  145.         ERR_GADGET,
  146.         NULL,
  147. };
  148.  
  149. struct IntuiText Curdir_text = {1,0,JAM1, -10,0,NULL,"S",NULL,};
  150. char cd_buf[MAXCD+1];
  151. struct StringInfo Curdir_str = 
  152. { &cd_buf, NULL, 0, MAXCD+1,   0, 0, 0, 0, 2,0, NULL, 0, NULL, };
  153. struct Gadget Curdir_gad =
  154. {
  155.         &Err_gad,
  156.         21,100,
  157.         588, 9,
  158.         GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
  159.         STRGADGET,
  160.         (APTR) &str_border,
  161.         NULL,
  162.         &Curdir_text,
  163.         0,
  164.         &Curdir_str,
  165.         CURDIR_GADGET,
  166.         NULL,
  167. };
  168.  
  169. /* Destination definitions */
  170. char cp_buf[MAXCD+1];
  171. struct IntuiText Cpdir_text = {1,0,JAM1,-10,0,NULL,"D",NULL,};
  172. struct StringInfo Cpdir_str = 
  173. { &cp_buf, NULL, 0, MAXCD+1,   0, 0, 0, 0, 2,0, NULL, 0, NULL, };
  174.  
  175. struct Gadget Cpdir_gad =
  176. {
  177.         &Curdir_gad,
  178.         21,111,
  179.         588, 9,
  180.         GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
  181.         STRGADGET,
  182.         (APTR) &str_border,
  183.         NULL,
  184.         &Cpdir_text,
  185.         0,
  186.         &Cpdir_str,
  187.         CPDIR_GADGET,
  188.         NULL,
  189. };
  190.  
  191. /************************************************************************/
  192. /*              File Select Gadget Declarations                         */
  193. /************************************************************************/
  194. struct Image slide_img;
  195. struct PropInfo slide_prop;
  196. struct Gadget Slide_gad =
  197. {
  198.     &Cpdir_gad,         /* Next gadget */
  199.     20, 14,             /* Left, Top edge */
  200.     20, 84,             /* Width Hieght */
  201.     GADGHNONE,          /* Flags */
  202.     GADGIMMEDIATE       /* More flags */
  203.     | RELVERIFY,
  204.     PROPGADGET,         /* Gadget type */
  205.     (APTR)&slide_img,   /* Border definition */
  206.     NULL,               /* Select render */
  207.     NULL,               /* Gadget text */
  208.     0,                  /* MutualExclude */
  209.     (APTR) &slide_prop, /* Special Info - proportional specification */
  210.     SLIDE_GADGET,
  211.     NULL,
  212. };
  213.  
  214. /* Button Gadget IDs */
  215.  
  216. struct IntuiText But_text[] =
  217. {
  218.         3,2,JAM2,0,0,NULL,"  df0:   ",NULL,
  219.         3,2,JAM2,0,0,NULL,"  df1:   ",NULL,
  220.         3,2,JAM2,0,0,NULL,"  df2:   ",NULL,
  221.         3,2,JAM2,0,0,NULL,"  dh0:   ",NULL,
  222.         3,2,JAM2,0,0,NULL,"  ram:   ",NULL,
  223.         3,2,JAM2,0,0,NULL,"   ALL   ",NULL,
  224.         3,2,JAM2,0,0,NULL,"  CLEAR  ",NULL,
  225.         3,2,JAM2,0,0,NULL,"  COPY   ",NULL,
  226.         3,2,JAM2,0,0,NULL," DELETE  ",NULL,
  227.         3,2,JAM2,0,0,NULL," RENAME  ",NULL,
  228.         3,2,JAM2,0,0,NULL," GETDIR  ",NULL,
  229.         3,2,JAM2,0,0,NULL," MAKEDIR ",NULL,
  230.         3,2,JAM2,0,0,NULL,"DELETEDIR",NULL,
  231.         3,2,JAM2,0,0,NULL," PARENT  ",NULL,
  232.         3,2,JAM2,0,0,NULL,"  ROOT   ",NULL,
  233.         3,2,JAM2,0,0,NULL,"  LIST   ",NULL,
  234.         3,2,JAM2,0,0,NULL,"  TYPE   ",NULL,
  235. #ifdef SHOW
  236.         3,2,JAM2,0,0,NULL,"SHOW ILBM",NULL,
  237. #endif
  238. };
  239.  
  240. struct Gadget But_gad[] =
  241. {
  242.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  243.             NULL,NULL,NULL,NULL,NULL,DF0_GADGET,NULL,
  244.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  245.             NULL,NULL,NULL,NULL,NULL,DF1_GADGET,NULL,
  246.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  247.             NULL,NULL,NULL,NULL,NULL,DF2_GADGET,NULL,
  248.      NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  249.             NULL,NULL,NULL,NULL,NULL,HD0_GADGET,NULL,
  250.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  251.             NULL,NULL,NULL,NULL,NULL,RAM_GADGET,NULL,
  252.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  253.             NULL,NULL,NULL,NULL,NULL,ALL_GADGET,NULL,
  254.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  255.             NULL,NULL,NULL,NULL,NULL,CLEAR_GADGET,NULL,
  256.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  257.             NULL,NULL,NULL,NULL,NULL,COPY_GADGET,NULL,
  258.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  259.             NULL,NULL,NULL,NULL,NULL,DELETE_GADGET,NULL,
  260.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  261.             NULL,NULL,NULL,NULL,NULL,RENAME_GADGET,NULL,
  262.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  263.             NULL,NULL,NULL,NULL,NULL, GETDIR_GADGET,NULL,
  264.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  265.             NULL,NULL,NULL,NULL,NULL,MAKEDIR_GADGET,NULL,
  266.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  267.             NULL,NULL,NULL,NULL,NULL,DELETEDIR_GADGET,NULL,
  268.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  269.             NULL,NULL,NULL,NULL,NULL,PARENT_GADGET,NULL,
  270.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  271.             NULL,NULL,NULL,NULL,NULL,ROOT_GADGET,NULL,
  272.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  273.             NULL,NULL,NULL,NULL,NULL,LIST_GADGET,NULL,
  274.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  275.             NULL,NULL,NULL,NULL,NULL,TYPE_GADGET,NULL,
  276.  #ifdef SHOW
  277.     NULL,5,174,72,8,GADGHCOMP,GADGIMMEDIATE | RELVERIFY,BOOLGADGET,
  278.             NULL,NULL,NULL,NULL,NULL,SHOW_GADGET,NULL,
  279. #endif
  280. };
  281.  
  282. /* BORDER DEFINITION FOR FILE SELECT AREA */
  283. USHORT Fil_pairs [] = { 40,15,  356,15,  356,98, 40,98, 40,15, };
  284. struct Border Fil_border =
  285. {
  286.         -1,-1,              /* Leftedge, Topedge */
  287.         1, 0, JAM1,        /* FrontPen, BackPen, Drawmode */
  288.         5,                 /* Number of Pairs */
  289.         (APTR) Fil_pairs,   /* XY, Pointer to XY pairs */
  290.         NULL,               /* More borders */
  291. };
  292.  
  293.  
  294. struct NewWindow nw =
  295. {
  296.         0,0,                    /* Start position */
  297.         640,134,                /* Width, height */
  298.         0,1,                    /* Detail, block pens */
  299.         WinIDCMP,               /* IDCMP flags */
  300.         WINDOWSIZING
  301.         | WINDOWDEPTH
  302.         | WINDOWDRAG
  303.         | REPORTMOUSE
  304.         | WINDOWCLOSE
  305.         | ACTIVATE
  306.         | RMBTRAP
  307.         | SMART_REFRESH,
  308.         &FIRST_GADGET,      /* First gadget in the list */
  309.         NULL,               /* User checkmark */
  310.         "DirUtil II ver. 1.4.1: original author - Chris Nicotra",
  311.         NULL,   
  312.         NULL,               /* Pointer to superbitmap */
  313.         100, 40, 640, 125,      /* Now sizeable */
  314.         WBENCHSCREEN,       /* Using the Workbench screen */
  315. };
  316.  
  317. /* The following structure is used to hold the directory entries */
  318. struct DirTable
  319. {
  320.         char  dt_fname[MAXCHAR];        /* File name */
  321.         short dt_select;                /* Select flag */
  322.         short dt_dir;                   /* Directory flag */
  323.         long  dt_size;                  /* File size */
  324. };
  325.  
  326. struct DirTable dirtable[MAXFILE+1];
  327. struct FileLock *InitialCurrentDirLock;
  328. struct FileLock *CurrentDirLock;
  329. struct FileLock *RAMSHOWLOCK;
  330. int cmp_dt();
  331. int numdir;
  332. int cur_index;
  333. int NILFD = 0;
  334. unsigned int mask = 0;
  335. static char curdir[MAXCD+1],requestedcd[MAXCD+1];
  336. void copy(), new_dir(), sel_file(), par_dir(), Print_to_screen();
  337. struct FileLock *oldlock;  /* lock to old directory */
  338.  
  339. main(argc,argv)
  340. char *argv[];
  341. {
  342.         struct Gadget *gad_ptr;
  343.         struct IntuiText *text_ptr;
  344.         ULONG MessageClass;
  345.         USHORT code;
  346.         int i;
  347.  
  348.         if(argc>2) {
  349.                 printf("usage: %s [SHOW]\n",*argv);
  350.                 exit(1);
  351.         }
  352.  
  353. #ifdef SHOW
  354.         /*  WBENCH      CLI AND SHOW OPTION                                                                     */
  355.         if(RAMSHOWLOCK = Lock(SHOWCMD,ACCESS_READ)) {
  356.                 UnLock(RAMSHOWLOCK);
  357.                 if(!(NILFD = Open("nil:",MODE_OLDFILE))) {
  358.                         puts("DirUtil FATAL: Can't open NIL: in main\n");
  359.                         exit(2);
  360.                 }
  361.         }
  362. #endif
  363.  
  364.         *cp_buf = 0;
  365.         strcpy(curdir,"ram:");
  366.         strcpy(requestedcd,curdir);
  367.         if(!(CurrentDirLock = Lock(curdir,ACCESS_READ))) {
  368.                 printf("DirUtil FATAL: Could not lock RAMdisk!\n");
  369.                 close_things();
  370.                 exit(4);
  371.         }
  372.         mask |= INITDIRLOCKOK;
  373.         InitialCurrentDirLock = CurrentDir(CurrentDirLock);
  374.  
  375.         /* Gadget initialization */
  376.         slide_prop.Flags = FREEVERT | AUTOKNOB;
  377.         slide_prop.VertBody = 0;
  378.         slide_prop.VertPot = 0x8000;
  379.  
  380.         /* Setup the button gadgets */
  381.         for (i=0;i<(BUT_LAST-BUT_FIRST)+1;i++) {
  382.                 gad_ptr = &But_gad[i];
  383.                 text_ptr = &But_text[i];
  384.  
  385.                 gad_ptr->LeftEdge = ((i%3) * 90) + 360;
  386.                 gad_ptr->TopEdge = ((i/3) * 15) + 14;
  387.  
  388.                 if (i)
  389.                     gad_ptr->NextGadget = &But_gad[i-1];
  390.                 else
  391.                     gad_ptr->NextGadget = &Slide_gad;
  392.  
  393.                 gad_ptr->GadgetText = text_ptr;
  394.  
  395.                 text_ptr->LeftEdge = 0;
  396.                 text_ptr->TopEdge = 0;
  397.         }
  398.  
  399.     if (!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library",0))) {
  400.         puts("DirUtil FATAL : no graphics library!!!\n");
  401.         close_things();
  402.         exit(5);
  403.     }
  404.     mask |= GRAPHICS;
  405.  
  406.     if (!(IntuitionBase = (struct IntuitionBase *)
  407.         OpenLibrary("intuition.library",0))) {
  408.         puts("DirUtil FATAL : no intuition here!!\n");
  409.         close_things();
  410.         exit(6);
  411.     }
  412.     mask |= INTUITION;
  413.  
  414.     if (!(w = (struct Window *) OpenWindow(&nw) )) {
  415.         puts("DirUtil FATAL : Could not open the window\n");
  416.         close_things();
  417.         exit(7);
  418.     }
  419.     mask |= WINDOW;
  420.  
  421.     /************ INITIALIZATION BEFORE main() loop *****************/
  422.         rp = w->RPort;
  423.         DrawBorder(rp,&Fil_border,0,0);
  424.  
  425.         getdir(curdir);
  426.         new_dir();
  427.  
  428.         display_error("O.K.",0);
  429.         RefreshGadgets(&FIRST_GADGET,w,NULL);
  430. #ifdef SHOW
  431.         if(!NILFD) OffGadget(&KILL_SHOW,w,NULL);
  432. #endif
  433.  
  434.         for (;;) {
  435.                 WaitPort(w->UserPort); 
  436.                 message = (struct IntuiMessage *) GetMsg(w->UserPort);
  437.                 MessageClass = message->Class;
  438.                 code = message->Code;
  439.                 ReplyMsg(message);
  440.                 switch (MessageClass) {
  441.                         case GADGETUP:
  442.                         case GADGETDOWN:
  443.                                 display_error("O.K.",0);
  444.                                 do_gadgets(message,w);
  445.                                 break;
  446.  
  447.                         case REFRESHWINDOW:
  448.                                 BeginRefresh(w); EndRefresh(w);
  449.                                 dis_files(cur_index);
  450.                                 DrawBorder(rp,&Fil_border,0,0);
  451.                                 break;
  452.  
  453.                         case CLOSEWINDOW:
  454.                                 close_things();
  455.                                 exit(0);
  456.                                 break;
  457.  
  458.                         case MOUSEBUTTONS:
  459.                                 if (code == SELECTDOWN)
  460.                                     sel_file();
  461.                                 break;
  462.  
  463.                         default:
  464.                                 break;
  465.                 } /*end switch*/
  466.         } /*end for*/
  467. }
  468.  
  469. do_gadgets(mes,win)
  470. struct IntuiMessage *mes;
  471. struct Window *win;
  472. {
  473.         struct FileLock *MakeDirLock;
  474.         struct Gadget *igad;
  475.         int gadgid;                 /* ID Code identifying which gadget */
  476.         int i;
  477.  
  478.         igad = (struct Gadget *) mes->IAddress;
  479.         gadgid = igad->GadgetID;
  480.         switch (gadgid) {
  481.                 case CURDIR_GADGET:
  482.                         ModifyIDCMP(w,0);
  483.                         nullterm(cd_buf,MAXCD);
  484.                         Curdir_str.NumChars = strlen(cd_buf);
  485.                         Curdir_str.BufferPos = strlen(cd_buf);
  486.                         getdir(cd_buf);
  487.                         new_dir();
  488.                         ModifyIDCMP(w,WinIDCMP);
  489.                         break;
  490.  
  491.                 case ERR_GADGET:
  492.                         nullterm(err_buf,MAXCD);
  493.                         err_str.NumChars = strlen(err_buf);
  494.                         err_str.BufferPos = strlen(err_buf);
  495.                         break;
  496.  
  497.                 case CPDIR_GADGET:      
  498.                         nullterm(cp_buf,MAXCD);
  499.                         Cpdir_str.NumChars = strlen(cp_buf);
  500.                         Cpdir_str.BufferPos = strlen(cp_buf);
  501.                         break;
  502.  
  503.                 case SLIDE_GADGET:
  504.                         rdis_files();
  505.                         break;
  506.  
  507.                 case ROOT_GADGET:
  508.                 case PARENT_GADGET:
  509.                         par_dir(gadgid);
  510.                         break;
  511.  
  512. #ifdef SHOW
  513.                 case SHOW_GADGET:
  514.                         display_error("SHOW : Now showing selected pictures.",0);
  515. #endif
  516.                 case DELETE_GADGET:
  517.                 case COPY_GADGET:
  518.                 case LIST_GADGET:
  519.                 case RENAME_GADGET:
  520.                 case TYPE_GADGET:
  521.                 case DELETEDIR_GADGET:
  522.                         action_on_selected(gadgid);
  523.                         break;
  524.  
  525.                 case MAKEDIR_GADGET:
  526.                 /* Attempt to create the named directory. Note that since
  527.                    the CurrentDir is whatever is in the CurrentDir gadget,
  528.                    if you don't give a complete path name, it will assume
  529.                    to create the directory in the current directory.
  530.                    Also, 1.1 CreateDir does not care if you try to create
  531.                    a directory entry on top of a file of the same name.
  532.                    Code around this...                                 */
  533.                         if(MakeDirLock = Lock(cp_buf,ACCESS_READ)) {
  534.                                 UnLock(MakeDirLock);
  535.                                 display_error("MAKEDIR ERROR : DIRECTORY / FILE ALREADY EXISTS. " ,IoErr());
  536.                                 break;
  537.                         } 
  538.                         if (!(MakeDirLock = CreateDir(cp_buf))) {
  539.                                 display_error("MAKEDIR ERROR : CreateDir FAILED. ", IoErr());
  540.                                 break;
  541.                         }
  542.                         UnLock(MakeDirLock);
  543.                         getdir(curdir);
  544.                         new_dir();
  545.                         break;
  546.  
  547.                 case DF0_GADGET:
  548.                         getdir("df0:"); new_dir(); break;
  549.                 case DF1_GADGET:
  550.                         getdir("df1:"); new_dir(); break;
  551.                 case DF2_GADGET:
  552.                         getdir("df2:"); new_dir(); break;
  553.                 case RAM_GADGET:
  554.                         getdir("ram:"); new_dir(); break;
  555.                 case HD0_GADGET:
  556.                         getdir("dh0:"); new_dir(); break;
  557.  
  558.                 case GETDIR_GADGET: 
  559.                         getdir(requestedcd);
  560.                         new_dir();
  561.                         break;
  562.  
  563.                 case CLEAR_GADGET:
  564.                         for (i=0;i<numdir;i++)
  565.                             dirtable[i].dt_select = 0;
  566.                         dis_files(cur_index);
  567.                         break;
  568.  
  569.                 case ALL_GADGET:
  570.                         for (i=0;i<numdir;i++)
  571.                                 if (!dirtable[i].dt_dir)
  572.                                         dirtable[i].dt_select = 1;
  573.                         dis_files(cur_index);
  574.                         break;
  575.  
  576.                 default:
  577.                         break;
  578.         }
  579. }
  580.  
  581.  
  582. getdir(DirToGet) 
  583. char *DirToGet;
  584. {
  585.         struct FileLock *filelock;
  586.         struct FileInfoBlock *fb;
  587.         char EffectiveDir[MAXCD+1];
  588.  
  589.         if (!(*DirToGet))
  590.                 strcpy(EffectiveDir,":");
  591.         else
  592.                 strcpy(EffectiveDir,DirToGet);
  593.  
  594.         /* If we cant open requested dir, don't change */
  595. TRYAGAIN:
  596.         if (!(filelock = Lock(EffectiveDir,ACCESS_READ))) {
  597.                 strcpy(EffectiveDir,curdir);
  598.                 display_error("ERROR : CAN'T LOCK REQUESTED DIRECTORY. ", IoErr());
  599.                 if(!(filelock = Lock(EffectiveDir,ACCESS_READ))) {
  600.                         display_error("FATAL : CAN'T LOCK CURRENT DIR. SWITCHING TO RAM: ", IoErr());
  601.                         strcpy(EffectiveDir,"RAM:");
  602.                         goto TRYAGAIN;
  603.                 }
  604.         }
  605.         /* Allocate the file info block */
  606.         fb = AllocMem(FBSIZE,MEMF_CLEAR | MEMF_PUBLIC);
  607.         if (!Examine(filelock,fb)) {
  608.                 FreeMem(fb,FBSIZE);
  609.                 UnLock(filelock);
  610.                 display_error("FATAL : CAN'T READ INFO BLOCK. SWITCHING TO RAM: ",IoErr());
  611.                 strcpy(EffectiveDir,"RAM:");
  612.                 goto TRYAGAIN;
  613.         }
  614.         if(fb->fib_DirEntryType < 0) {  /* ITS A FILE- NOT A DIRECTORY  */
  615.                 strcpy(EffectiveDir,curdir);/* Forget request, use current*/
  616.                 FreeMem(fb,FBSIZE);
  617.                 UnLock(filelock);
  618.                 display_error("WARNING : DIRECTORY REQUESTED WAS REGULAR FILE - NO CHANGES. ", IoErr());
  619.                 goto TRYAGAIN;
  620.         }
  621.  
  622.         /* Copy directory string into gadget structure */
  623.         strcpy(cd_buf,EffectiveDir);
  624.         Curdir_str.NumChars = strlen(EffectiveDir);
  625.         Curdir_str.BufferPos = strlen(EffectiveDir);
  626.         strcpy(curdir,EffectiveDir);
  627.         strcpy(requestedcd,EffectiveDir);
  628.         RefreshGadgets(&Cpdir_gad,w,NULL);
  629.  
  630.         numdir = 0;
  631.         cur_index = 0;
  632.  
  633.         /* Loop through each of the files in this directory */
  634.         while (ExNext(filelock,fb)) {
  635.                 if (fb->fib_DirEntryType < 0)
  636.                         dirtable[numdir].dt_dir = 0;
  637.                 else
  638.                     dirtable[numdir].dt_dir = -1;
  639.                 dirtable[numdir].dt_select = 0;
  640.                 dirtable[numdir].dt_size = fb->fib_Size;
  641.                 strncpy(dirtable[numdir].dt_fname,fb->fib_FileName,MAXCHAR);
  642.                 nullterm(dirtable[numdir].dt_fname,MAXCHAR);
  643.  
  644.                 if (++numdir == MAXFILE)
  645.                     break;
  646.         }
  647.  
  648.         /* Sort the table */
  649.         qsort(dirtable,numdir,(sizeof (struct DirTable)),cmp_dt); 
  650.         FreeMem(fb,FBSIZE);
  651.         UnLock(CurrentDirLock);         /* Release old CD lock      */
  652.         UnLock(filelock);               /* Release new request lock */
  653.         CurrentDirLock = Lock(EffectiveDir);
  654.         CurrentDir(CurrentDirLock);     /* MAKE IT THE CURRENT DIRECTORY */
  655. }
  656.  
  657.  
  658.  
  659. rdis_files()
  660. {
  661.     USHORT Vpot;
  662.         int numd;
  663.         int pos;
  664.  
  665.         if (numdir > MAXFNAME) {
  666.         Vpot = slide_prop.VertPot;
  667.                 Vpot >>= 1;
  668.                 Vpot &= 0x7fff;
  669.                 numd = numdir - MAXFNAME;
  670.                 pos = ((float) Vpot / (float) 0x7fff) * numd;
  671.                 cur_index = pos;
  672.                 dis_files(pos);
  673.         }
  674. }
  675.  
  676. /**********************************************************************
  677. *    new_dir - New directory
  678. *    Purpose: To display a new directory and initialize the slide gadget.
  679. **********************************************************************/
  680. void new_dir()
  681. {
  682.         USHORT Vbody;
  683.  
  684.         if (numdir <= MAXFNAME) 
  685.                 Vbody = 0xffff;
  686.         else {
  687.             Vbody = ((float) 0x7fff) / (((float) numdir) / ((float) MAXFNAME));
  688.                 Vbody <<= 1;
  689.         }
  690.         cur_index = 0;
  691.         ModifyProp(&Slide_gad,w,NULL,slide_prop.Flags,0,0,0,Vbody);
  692.         dis_files(0);
  693.         return;
  694. }
  695.  
  696. /**********************************************************************
  697. *    dis_files - Display files
  698. *    Purpose:    To display a page of file names
  699. *    Parameters: pos - The position in the file list
  700. **********************************************************************/
  701. dis_files(pos)
  702. int pos;
  703. {
  704.         int i;
  705.  
  706.         for (i=0;i<MAXFNAME;i++)
  707.                 dis_name(i+pos,i);
  708. }
  709.  
  710. /***********************************************************************
  711. *    dis_name - Display a file name
  712. *    Purpose: To display a file name
  713. *    Parameters:
  714. *        file - File index (into dirtable) or -1 for blank entry
  715. *        pos - The position in the file list
  716. **********************************************************************/
  717. dis_name(file,pos)
  718. int file;
  719. int pos;
  720. {
  721.         static char file_name[MAXCHAR+8];
  722.         static struct IntuiText file_text = {
  723.             2,0,JAM2,45,15,NULL,(UBYTE *)file_name, NULL };
  724.  
  725.         /* Set the top position */
  726.         file_text.TopEdge = (pos*8)+16;
  727.  
  728.         if (file == -1 || file >= numdir) {
  729.                 sprintf(file_name,"%-38.38s","");
  730.                 file_text.FrontPen = 2;
  731.                 file_text.BackPen = 2;  /* black */
  732.         } else {
  733.                 if (dirtable[file].dt_dir) {
  734.                         sprintf(file_name,"%-30.30s%-8.8s",dirtable[file].dt_fname,"");
  735.                         if (dirtable[file].dt_select) {
  736.                                 file_text.FrontPen = 2; /* Black on Orange */
  737.                                 file_text.BackPen = 3;
  738.                         } else {
  739.                                 file_text.FrontPen = 3; /* Orange on Black */
  740.                                 file_text.BackPen = 2;
  741.                         }
  742.                 } else {
  743.                         sprintf(file_name,"%-30.30s %7ld",dirtable[file].dt_fname,
  744.                         dirtable[file].dt_size);
  745.                         if (dirtable[file].dt_select) {
  746.                                 file_text.FrontPen = 2; /* Black on White */
  747.                                 file_text.BackPen = 1;
  748.                         } else {
  749.                                 file_text.FrontPen = 1; /* White on Black  */
  750.                                 file_text.BackPen = 2;
  751.                         }
  752.                 }
  753.         }
  754.  
  755.         /* Display the text */
  756.         PrintIText(rp,&file_text,0,0);
  757. }
  758.  
  759. /**********************************************************************
  760. *    sel_file - Select file
  761. *
  762. *    Purpose: To check if a file has been selected and the select
  763. *        or unselect it
  764. **********************************************************************/
  765. void sel_file()
  766. {
  767.         int file,i;
  768.         char *ptr;
  769.  
  770.         if (message->MouseX < 45 || message->MouseX > 351)
  771.             return;
  772.         if (message->MouseY < 16 || message->MouseY >= (MAXFNAME*8+16))
  773.             return;
  774.         file = message->MouseY - 16;
  775.         file /= 8;
  776.         if((!numdir) || (file > MAXFNAME) || ((file+cur_index) > numdir))
  777.             return;
  778.  
  779.         /* Check to see if selection is a directory, or regular file    */
  780.         /* For now, only allow one directory to be selected at a time   */
  781.         if (dirtable[file+cur_index].dt_dir) {
  782.                 for(i=0;i<numdir;i++)
  783.                         if((dirtable[i].dt_dir)&&(i != file+cur_index))
  784.                                 dirtable[i].dt_select = 0;
  785.                 ptr = curdir + strlen(curdir) - 1;
  786.                 if(dirtable[file+cur_index].dt_select ^= 1) 
  787.                         sprintf(requestedcd,"%s%s%s",curdir,((*ptr == ':') ? "":"/"),
  788.                         dirtable[file+cur_index].dt_fname);
  789.                 else
  790.                         strcpy(requestedcd,curdir);
  791.                 dis_files(cur_index);
  792.                 return;
  793.         }
  794.         dirtable[file+cur_index].dt_select ^= 1;
  795.         dis_name(file+cur_index,file);
  796. }
  797.  
  798. action_on_selected(gadgid) /* Copy,Delete,ShowILBM,List,Type,DELETEDIR */
  799. int gadgid;
  800. {
  801.         struct IntuiMessage *message;
  802.         int i;
  803.         char filename[MAXCD+MAXCHAR+2];
  804.         char *ptr;
  805.     short isdir;
  806. #ifdef SHOW
  807.         char command[MAXCD+MAXCHAR+2+SHOWNAMELENGTH];/* See comments in #defines*/
  808. #endif
  809.  
  810.         /* At each iteration, check for any IntuiMessages that would signal
  811.            user wants to halt operation: GADGETUP(he hit a gadget) or
  812.            MOUSEBUTTONS(button press on something we dont recognize) */
  813.  
  814.         ModifyIDCMP(w,GADGETUP | MOUSEBUTTONS);
  815.         for (i=0;i<numdir;i++) {
  816.             if(message = (struct IntuiMessage *) GetMsg(w->UserPort)) {
  817.                 ReplyMsg(message);
  818.                 display_error("INTERRUPT : OPERATION HALTED.",0);
  819.                 break; 
  820.             }
  821.  
  822.             if (dirtable[i].dt_select) {
  823.         isdir = dirtable[i].dt_dir;
  824.                 ptr = curdir + strlen(curdir)-1;
  825.                 if (*ptr == ':')
  826.                     sprintf(filename,"%s%s",curdir,dirtable[i].dt_fname);
  827.                 else
  828.                     sprintf(filename,"%s/%s",curdir,dirtable[i].dt_fname);
  829.  
  830.                 switch (gadgid) {
  831.                     case DELETE_GADGET:
  832.                         if(isdir) {
  833.                             display_error("DELETE ERROR : FILE IS A DIRECTORY.",0);
  834.                             break;
  835.                         }
  836.                         if(!(DeleteFile(filename)))
  837.                             display_error("DELETE ERROR : COULD NOT DELETE REQUESTED FILE. ", IoErr());
  838.                         break;
  839.  
  840.                     case DELETEDIR_GADGET:
  841.                         if(!isdir) {
  842.                             display_error("DELETEDIR ERROR : FILE IS NOT A DIRECTORY. ",0);
  843.                             break;
  844.                         }
  845.                         if(!(DeleteFile(filename)))
  846.                             display_error("DELETEDIR ERROR : COULD NOT DELETE REQUESTED DIRECTORY. ", IoErr());
  847.                         break;
  848.  
  849.                     case COPY_GADGET:
  850.                         copy(filename,cp_buf);
  851.                         break;
  852.  
  853. #ifdef SHOW
  854.                     case SHOW_GADGET:
  855.                         if(NILFD && !isdir) {
  856.                             sprintf(command,"%s %s",SHOWCMD,filename);
  857.                             Execute(command,0,NILFD);
  858.                         }
  859.                         break;
  860. #endif
  861.  
  862.                     case LIST_GADGET:
  863.                         /* K L U D G E */
  864.                         ptr = &filename;
  865.                         while((*ptr != ':')&&(*ptr != '\0')) ptr++;
  866.                         printf("%s\n",ptr);
  867.                         break;
  868.  
  869.                     case TYPE_GADGET:
  870.             if(!isdir)
  871.                 Print_to_screen(filename);
  872.                         break;
  873.  
  874.                     case RENAME_GADGET:
  875.                         /* NOTE: you must select the file to be renamed -
  876.                            this doesnt check cd_buf for a filename!     */
  877.                         if(!(Rename(filename,cp_buf))) 
  878.                             display_error("RENAME ERROR : CANNOT RENAME TO REQUESTED PATH. ", IoErr());
  879.                         break;
  880.  
  881.                     default:
  882.                         break;
  883.                 } /*switch*/
  884.                 if(RENAME_GADGET == gadgid)
  885.                     break; /* RENAME FIRST FILE SELECTED ONLY! */
  886.                 } /* if selected */
  887.         } /* for all */
  888.  
  889. #ifdef SHOW
  890.         if((SHOW_GADGET == gadgid)||(LIST_GADGET == gadgid)||
  891.        (TYPE_GADGET == gadgid)) {
  892. #else
  893.         if((LIST_GADGET == gadgid)||(TYPE_GADGET == gadgid)) {
  894. #endif
  895.                 dis_files(cur_index);
  896.         } else {
  897.                 getdir(curdir);
  898.                 new_dir();
  899.         }
  900.         ModifyIDCMP(w, WinIDCMP);
  901. }
  902.  
  903. void par_dir(gadgid) /* Parent and Root */
  904. int gadgid;
  905. {
  906.         char *ptr;                 /* With this, we may change curdir  */
  907.  
  908.         ModifyIDCMP(w,0);
  909.         ptr = curdir+strlen(curdir)-1;
  910.         if(PARENT_GADGET == gadgid)
  911.                 for (;ptr >= curdir;ptr--) {
  912.                         if (*ptr == ':') { 
  913.                                 *(ptr+1) = 0; 
  914.                                 break;
  915.                         }
  916.                         if (*ptr == '/') { 
  917.                                 *ptr = 0;
  918.                                 break;
  919.                         }
  920.                 }
  921.         else    /* Gadget was root. Scan back to :  */
  922.                 for (;ptr >= curdir;ptr--) 
  923.                         if (*ptr == ':') {
  924.                                 *(ptr+1) = 0;
  925.                                 break;
  926.                         }
  927.  
  928.         getdir(curdir);
  929.         new_dir();
  930.         ModifyIDCMP(w,WinIDCMP);
  931.         return;
  932. }
  933.  
  934. /* The following function is used to compare two directory entries */
  935. cmp_dt(dt1,dt2)
  936. struct DirTable *dt1,*dt2;
  937. {
  938.    char *ptr1,*ptr2;
  939.    int c1,c2;
  940.  
  941.    for (ptr1=dt1->dt_fname,ptr2=dt2->dt_fname;*ptr1 && *ptr2;ptr1++,ptr2++) {
  942.         c1 = *ptr1;
  943.         c2 = *ptr2;
  944.  
  945.         if (c1 >= 'A' && c1 <= 'Z') {
  946.                 c1 -= 'A';
  947.                 c1 += 'a';
  948.         }
  949.  
  950.         if (c2 >= 'A' && c2 <= 'Z') {
  951.                 c2 -= 'A';
  952.                 c2 += 'a';
  953.         }
  954.  
  955.         if (c1 > c2)
  956.                 return (-1);
  957.  
  958.         if (c1 < c2)
  959.                 return (1);
  960.    }
  961.  
  962.    if (*ptr1)
  963.         return (-1);
  964.  
  965.    if (*ptr2)
  966.         return (1);
  967.  
  968.    return (0);
  969. }
  970.  
  971. void copy(s,pc)
  972. char *s;
  973. char *pc;
  974. {
  975.         struct FileHandle  *copyin;
  976.         struct FileHandle  *copyout;
  977.         int iosize;
  978.         int actual;
  979.         char *copybuf;
  980.         char work[300];
  981.         struct FileLock *fl;
  982.         char *ptr;
  983.         char *ptr1;
  984.  
  985.         if (!(copyin = Open(s,MODE_OLDFILE)))
  986.                 return;
  987.  
  988.         if (!*pc) {
  989.                 display_error("COPY ERROR : NO DESTINATION PATH GIVEN.",0);
  990.                 return;
  991.         }
  992.  
  993.         if ((fl = Lock(pc,ACCESS_READ))) {
  994.                 UnLock(fl);
  995.                 ptr = strlen(pc) + pc - 1;
  996.                 for (ptr1=s+strlen(s)-1;ptr1 > s;ptr1--) {
  997.                         if (*ptr1 == '/' || *ptr1 == ':')
  998.                                 break;
  999.                 }
  1000.                 if (*ptr1 == '/' || *ptr1 == ':')
  1001.                         ptr1++;
  1002.                 if (*ptr == ':')
  1003.                         sprintf(work,"%s%s",pc,ptr1);
  1004.                 else
  1005.                     sprintf(work,"%s/%s",pc,ptr1);
  1006.         } else {
  1007.                 display_error("COPY ERROR : ILLEGAL DESTINATION PATH. ", IoErr());
  1008.                 Close(copyin);
  1009.                 return;
  1010.         }
  1011.  
  1012.         if (!strcmp(work,s)) {
  1013.                 display_error("COPY ERROR : CANNOT COPY FILE TO ITSELF. ",0);
  1014.                 Close(copyin);
  1015.                 return;
  1016.         }
  1017.  
  1018.         if (!(copyout = Open(work, MODE_NEWFILE))) {
  1019.                 display_error("COPY ERROR : COPY CANNOT WRITE TO REQUESTED PATH. ", IoErr());
  1020.                 Close(copyin);
  1021.                 return;
  1022.         } else {
  1023.                 /* Determine the length of the file */
  1024.                 iosize = Seek(copyin, 0, OFFSET_END);
  1025.                 iosize = Seek(copyin, 0, OFFSET_BEGINING);
  1026.  
  1027.                 /* Allocate memory for the copy buffer */
  1028.                 do {
  1029.                         copybuf = AllocMem(iosize, MEMF_PUBLIC|MEMF_CLEAR);
  1030.                         if (copybuf == 0)
  1031.                                 iosize = iosize/2;
  1032.                 } while (copybuf == 0 & iosize > 512);
  1033.  
  1034.                 /* Copy the file */
  1035.                 do {
  1036.                         actual = Read(copyin, copybuf, iosize);
  1037.                         if (Write(copyout, copybuf, actual) != actual)
  1038.                                 break;
  1039.                 } while (actual == iosize);
  1040.  
  1041.                 /* Free the copy buffer */
  1042.                 FreeMem(copybuf, iosize);
  1043.  
  1044.                 /* Close the input and output buffers */
  1045.                 Close(copyout);
  1046.                 Close(copyin);
  1047.         }
  1048. }
  1049.  
  1050. nullterm(str,len)       /* End a string with a null */
  1051. char *str;
  1052. int len;
  1053. {
  1054.         int i;
  1055.  
  1056.         str[len] = 0; 
  1057.         for (i=len;len >= 0;len--) {
  1058.             if (str[i] != ' ' && str[i])
  1059.                     break;
  1060.                 str[i] = 0;
  1061.         }
  1062. }
  1063.  
  1064. display_error(errormsg,doserrnum)
  1065. char *errormsg;
  1066. long doserrnum;
  1067. {
  1068.         strcpy(err_buf,errormsg);
  1069.         if(doserrnum)
  1070.                 sprintf(err_buf,"%s (Dos Error %d)",err_buf,doserrnum);
  1071.         err_str.NumChars = strlen(err_buf);
  1072.         err_str.BufferPos = strlen(err_buf);
  1073.         RefreshGadgets(&Err_gad,w,NULL);
  1074. }
  1075.  
  1076. close_things()
  1077. {
  1078.     if (mask & WINDOW)
  1079.         CloseWindow(w);
  1080.  
  1081.     if (mask & GRAPHICS)
  1082.         CloseLibrary(GfxBase);
  1083.  
  1084.     (void) OpenWorkBench();
  1085.  
  1086.     if (mask & INTUITION)
  1087.         CloseLibrary(IntuitionBase);
  1088.  
  1089. #ifdef SHOW
  1090.         if(NILFD) {
  1091.                 Close(NILFD);
  1092.         }
  1093. #endif
  1094.  
  1095.     if(mask & INITDIRLOCKOK) {
  1096.         CurrentDir(InitialCurrentDirLock);
  1097.         UnLock(CurrentDirLock);
  1098.     }
  1099. }
  1100.  
  1101. qsort( v, n, size, comp)
  1102. char *v;
  1103. int n;
  1104. int size;
  1105. int (*comp)();
  1106. {
  1107.         int gap, i, j, x, cnt;
  1108.         char temp, *p1, *p2;
  1109.  
  1110.         cnt = 0;
  1111.         for (gap=n/2; gap > 0 ; gap /= 2)
  1112.                 for (i=gap; i<n; i++)
  1113.                         for (j = i-gap; j >= 0; j -= gap)
  1114.                                 if ( (*comp) ( (p1=v+j*size), (p2=v+(j+gap)*size) ) < 0) {  
  1115.                                         cnt++;
  1116.                                         /* exchange them */
  1117.                                         for (x=0; x<size; x++) {
  1118.                                                 temp = *p1;
  1119.                                                 *p1++ = *p2;
  1120.                                                 *p2++ = temp;
  1121.                                         }
  1122.                                 }
  1123.         return(cnt);
  1124. }
  1125. void Print_to_screen(ptr)
  1126. char *ptr[];
  1127. {
  1128.  
  1129. int i, len, len2;    /* loop and counter variables */
  1130. int linecount = 1;      /* count of lines displayed to screen */
  1131. int done = FALSE;    /* boolean variables */
  1132. unsigned char c;     /* character read from keyboard */
  1133. unsigned char work[80];    /* string space used for messages */
  1134. unsigned char buf[512];       /* buffer to hold one block of the file */
  1135. int filepos;
  1136.  
  1137. struct FileHandle *window = NULL;    /* file handle for raw window to screen */
  1138. struct FileHandle *workfp = NULL;    /* file handle to file to be displayed*/
  1139.  
  1140.   workfp = Open(ptr, MODE_OLDFILE); /*Try to open the file to display. */
  1141.   if(workfp == NULL)
  1142.      done = TRUE;
  1143.   else{
  1144.    /* Open a Workbench window.  If there is an error, stop.*/
  1145.      strcpy(work, "Raw:0/0/640/199/Listing of ");
  1146.      strcat(work, ptr);
  1147.      strcat(work, "");
  1148.   window = Open(work, MODE_NEWFILE);
  1149.   if(window == NULL)
  1150.      done = TRUE;
  1151.       }
  1152.   strcpy(work, "\x1b[33m<CR>\x1b[2m");
  1153.   strcat(work, " advances one line, ");
  1154.   strcat(work, "\x1b[33mSpace\x1b[2m");
  1155.   Write(window, work, strlen(work));
  1156.   strcpy(work, " one page, ");
  1157.   strcat(work, "'\x1b[33mb\x1b[2m' '\x1b[33m<\x1b[2m' back, ");
  1158.   strcat(work, "\x1b[33mESC\x1b[2m");
  1159.   strcat(work, " aborts.\n\x1b[0m");
  1160.   Write(window, work, strlen(work));
  1161.   if (!done)
  1162.      do{
  1163.          /* Read a block of the file, search for the end of line.*/
  1164.         len = Read(workfp, buf, 512);
  1165.         len2 = 0;
  1166.         while (len2<len){
  1167.            for (i=len2; buf[i] != '\n' && i<511; i++)
  1168.               ;
  1169.            Write(window, &buf[len2], i-len2+1);
  1170.        linecount += (i - len2 + 1)/79 + 1;
  1171.            len2 = i + 1;
  1172.            if (linecount >= 22 && buf[i] == '\n'){
  1173.               linecount = 1;
  1174.                   /* print the messages in color 3 */
  1175.           strcpy(work, "\x1b[33mPress SPACE for more...\x1b[0m");
  1176.           Write(window, work, strlen(work));
  1177.                   /* wait for a key */
  1178.            while(Read(window, &c, 1),c != ' ') {
  1179.                  if (c == BRK || c == ESC){
  1180.             len = 0;    /* short circuit the loop */
  1181.             break;
  1182.          } else if (c == '\r'){
  1183.                   /* RETURN scrolls by one line */
  1184.             linecount = 21;
  1185.             break;
  1186.          } else if (c == 'b') {
  1187.             Write(window,"\x1b[1;1H\x1b[J",9);
  1188.             filepos = Seek(workfp,0,OFFSET_CURRENT);
  1189.             filepos = max(0,filepos-2048);
  1190.             Seek(workfp,filepos,OFFSET_BEGINNING);
  1191.             len2 = len;
  1192.             break;
  1193.          } else if (c == '<') {
  1194.             Write(window,"\x1b[1;1H\x1b[J",9);
  1195.             Seek(workfp,0,OFFSET_BEGINNING);
  1196.             len2 = len;
  1197.             break;
  1198.          }
  1199.           }
  1200.                   /* erase the message */
  1201.           strcpy(work, "\r                       \r");
  1202.           Write(window, work, strlen(work));
  1203.        }
  1204.     }
  1205.      }while(len == 512);
  1206.  
  1207.               /* If not aborting the program */
  1208.     if (!done){
  1209.        strcpy(work, "\n\x1b[33mEnd of File.  Press SPACE\x1b[0m");
  1210.        Write(window, work, strlen(work));
  1211.             /* Wait for spacebar to quit */
  1212.        while(Read(window, &c, 1), c != ' ')
  1213.            ;
  1214.        }
  1215.  
  1216.     if(workfp)
  1217.        Close(workfp);
  1218.     if(window)
  1219.        Close(window);
  1220.     return;
  1221. }
  1222.                                                                  
  1223.